/*
 * Problem: 最小生成树
 * Author: Yuanshun L
 * Created: 23-Nov-2021
 * Topic: Kruskal算法
 */

#include<iostream>
#include<algorithm>
using namespace std;

// ------------ unite-find set -----------

const int maxn = 100 + 5;
int par[maxn];
int height[maxn]; // height

// init 
void init_union_find(int nn){
    for(int i=0;i<nn;i++){
        par[i] = i;
        height[i] = 0;
    }
}

// find the root of a node
int find2(int x){
    while(x != par[x]){
        x = par[x];
    }
    return x;
}

// unite two tree while x belongs a tree and y another
void unite(int x,int y){
    int rootx,rooty;
    rootx = find2(x);
    rooty = find2(y);
    if(rootx == rooty)
        return;
    if(height[rooty] < height[rootx])
        par[rooty] = rootx;
    else
        par[rootx] = rooty;
}

// judge if two node are in the same tree
bool same(int x,int y) {
    return find2(x) == find2(y);
}

// ------------ Code Achievement -------------
struct edge{
    int v,u,w;
    edge(int v=0,int u=0,int w=0):v(v),u(u),w(w){}
    bool operator<(edge &e){
        return w < e.w;
    }
};
int n,m; // the number of node and edge
edge edges[maxn*maxn]; // the edge set

void read_data(){
    int v,u,w;
    cin >> n >> m;
    for(int i=0;i<m;i++){
        cin >> v >> u >> w;
        edges[i] = edge(v,u,w);
    }
}
// Use the union finding set to efficiently determine creating a circle or not.
// Krustal Algorithm
void solve(){
    sort(edges,edges+m);
    init_union_find(n);
    int ans = 0;
    for(int i=0;i<m;i++){
        edge e = edges[i];
        if(same(e.v,e.u)) continue;
        ans += e.w;
        unite(e.v,e.u);
    }
    cout << "Short Path Value: " << ans << endl;
}

int main(){

    freopen("data.in","r",stdin);
    freopen("data.out","w",stdout);

    read_data();
    solve();

    return 0;

}